
#include "TreeInstance.h"

// [*] and_or_tree::CTreeInstance

//int and_or_tree::CTreeInstance::Para_GenPixelCandidate_LenTh = 10;
//double and_or_tree::CTreeInstance::Para_GenPixelCandidate_DirTh = PI/6.0;
//int and_or_tree::CTreeInstance::Para_GenPixelCandidate_PixMargin = 5;
//double and_or_tree::CTreeInstance::Para_GenPixelCandidate_PixSampleRate = 1.0;

void and_or_tree::CTreeInstance::__Init_IBF_and_IPPFE()
{
	CDataStructureTools::MyRelease_Single(pIFB);

	pIFB = new CImageFilterBank();
	pIFB->myInit();

	CImageFilter_RGB* pFilter_RGB = pIFB->pBasicFilter_RGB;

	CImageFilter_Gradient* pFilter_Gradient = new CImageFilter_Gradient(0.0, true);
	pFilter_Gradient->PushBackInputResponse(pFilter_RGB, 0);
	pFilter_Gradient->PushBackInputResponse(pFilter_RGB, 1);
	pFilter_Gradient->PushBackInputResponse(pFilter_RGB, 2);
	pIFB->PushBackFilter(pFilter_Gradient);

	CImageFilter_Gray* pFilter_Gray = new CImageFilter_Gray();
	pFilter_Gray->PushBackInputResponse(pFilter_RGB, 0);
	pFilter_Gray->PushBackInputResponse(pFilter_RGB, 1);
	pFilter_Gray->PushBackInputResponse(pFilter_RGB, 2);
	pIFB->PushBackFilter(pFilter_Gray);

	CImageFilter_CannyEdge* pFilter_CannyEdge = new CImageFilter_CannyEdge(1.0, 0.30, 0.60, 0.0, (PI+PI)/1.0, true);
	//pFilter_CannyEdge->PushBackInputResponse(pFilter_RGB, 0);
	//pFilter_CannyEdge->PushBackInputResponse(pFilter_RGB, 1);
	//pFilter_CannyEdge->PushBackInputResponse(pFilter_RGB, 2);
	pFilter_CannyEdge->PushBackInputResponse(pFilter_Gray, 0);
	pIFB->PushBackFilter(pFilter_CannyEdge);

	CImageFilter_EdgeForest* pFilter_EdgeForest = new CImageFilter_EdgeForest(0.5, true, 10, PI/6.0);
	pFilter_EdgeForest->PushBackInputResponse(pFilter_CannyEdge, 0);
	pFilter_EdgeForest->PushBackInputResponse(pFilter_CannyEdge, 1);
	pIFB->PushBackFilter(pFilter_EdgeForest);

	pFilter_Gradient->PushBackOutput(0);
	pFilter_Gradient->PushBackOutput(1);
	pFilter_CannyEdge->PushBackOutput(0);
	pFilter_EdgeForest->PushBackOutput(0);

	pIFB->GetOutputDimension(true);

	fIsIPPFEshared = false;
	if (CLeafNode::pIPFE_Prototype == NULL)
		pIPPFE_Leaf = NULL;
	else
		pIPPFE_Leaf = new CImagePyramidPositionFeatureExtractor(CLeafNode::pIPFE_Prototype->myClone(), 3);
}

and_or_tree::CTreeInstance::CTreeInstance()
{
	pIFB = NULL;
	pIPPFE_Leaf = NULL;
	__Init_IBF_and_IPPFE();

	pTree = NULL;
	ParsedInstanceList.Clear();
	InstanceSet.Clear();
	ClearImage();
	CandidatePixelList.Clear();

	SetPixelCandidateGeneratingParameters(5, 1.0);
}

void and_or_tree::CTreeInstance::SetPixelCandidateGeneratingParameters(int PixMargin, double PixSampleRate)
{
	Para_GenPixelCandidate_PixMargin = PixMargin;
	Para_GenPixelCandidate_PixSampleRate = PixSampleRate;
}

void and_or_tree::CTreeInstance::myRelease()
{
	CDataStructureTools::MyRelease_Single(pIFB);

	if (fIsIPPFEshared)
		pIPPFE_Leaf = NULL;
	else
	{
		if (pIPPFE_Leaf && CLeafNode::pCurrentIPPFE==pIPPFE_Leaf) CLeafNode::SetCurrentIPPFE(NULL);
		CDataStructureTools::MyRelease_Single(pIPPFE_Leaf);
	}
}

and_or_tree::CTreeInstance::~CTreeInstance()
{
	myRelease();
}

void and_or_tree::CTreeInstance::ShareIPPFE_From(const CTreeInstance& AnotherIntance)
{
	if (!fIsIPPFEshared)
	{
		if (pIPPFE_Leaf && CLeafNode::pCurrentIPPFE==pIPPFE_Leaf) CLeafNode::SetCurrentIPPFE(AnotherIntance.pIPPFE_Leaf);
		CDataStructureTools::MyRelease_Single(pIPPFE_Leaf);
	}

	fIsIPPFEshared = true;
	pIPPFE_Leaf = AnotherIntance.pIPPFE_Leaf;
}

void and_or_tree::CTreeInstance::CloneDataFrom(const CTreeInstance& AnotherInstance, bool fShareIPPFE)
{
	InitTree(AnotherInstance.pTree);
	InitImage(AnotherInstance.imgSrcRGB);
	if (fShareIPPFE)
		ShareIPPFE_From(AnotherInstance);
	CandidatePixelList = AnotherInstance.CandidatePixelList;
	ParsedInstanceList = AnotherInstance.ParsedInstanceList;
	InstanceSet = AnotherInstance.InstanceSet;
}

and_or_tree::CTreeInstance::CTreeInstance(const CTreeInstance& AnotherIntance)
{
	pIFB = NULL;
	pIPPFE_Leaf = NULL;
	__Init_IBF_and_IPPFE();

	CloneDataFrom(AnotherIntance, false);
}

and_or_tree::CTreeInstance& and_or_tree::CTreeInstance::operator = (const CTreeInstance& AnotherIntance)
{
	if (&AnotherIntance == this) return *this;

	CloneDataFrom(AnotherIntance, false);
	return *this;
}

void and_or_tree::CTreeInstance::InitTree(const CAbstractTree* pFixedAndOrTree)
{
	this->pTree = pFixedAndOrTree;
	ClearAllInstances();
}

void and_or_tree::CTreeInstance::ClearAllInstances()
{
	CParsedInstance TempParsedInstance;
	TempParsedInstance.ClearAll();

	ParsedInstanceList.Resize(pTree->NodeAmount);
	ParsedInstanceList.Fill(TempParsedInstance);

	CSimpleTypeArray<CInstanceChoice> TempInstanceChoiceList;
	TempInstanceChoiceList.Clear();

	InstanceSet.Resize(pTree->NodeAmount);
	InstanceSet.Fill(TempInstanceChoiceList);
}

CSimpleTypeArray<and_or_tree::CInstanceChoice>& and_or_tree::CTreeInstance::GetInstanceList(int NodeIndex)
{
	return InstanceSet.pElement[NodeIndex];
}

and_or_tree::CInstanceChoice& and_or_tree::CTreeInstance::GetInstance(int NodeIndex, int InstanceIndex)
{
	return InstanceSet.pElement[NodeIndex].pElement[InstanceIndex];
}

const CSimpleTypeArray<and_or_tree::CInstanceChoice>& and_or_tree::CTreeInstance::GetInstanceList(int NodeIndex) const
{
	return InstanceSet.pElement[NodeIndex];
}

const and_or_tree::CInstanceChoice& and_or_tree::CTreeInstance::GetInstance(int NodeIndex, int InstanceIndex) const
{
	return InstanceSet.pElement[NodeIndex].pElement[InstanceIndex];
}

void and_or_tree::CTreeInstance::ClearImage()
{
	imgSrcRGB.assign(1,1,1,1,0);
	W = H = WH = 0;
	OrientationList = NULL;
	EdgeMap = NULL;
	if (pIPPFE_Leaf)
		pIPPFE_Leaf->SetImage(imgSrcRGB, "");
}

void and_or_tree::CTreeInstance::InitImage(const CImg<int>& imgSrcRGB)
{
	this->imgSrcRGB = imgSrcRGB;

	W = imgSrcRGB.dimx();
	H = imgSrcRGB.dimy();
	WH = W * H;
	pIFB->Work(imgSrcRGB);
	OrientationList = pIFB->GetOutput(1);
	EdgeMap = pIFB->GetOutput(3);

	pIPPFE_Leaf->SetImage(imgSrcRGB, "");

	ClearAllInstances();

	this->GenerateCandidatePixelList();
}

void and_or_tree::CTreeInstance::InitImage(string strFN_Image)
{
	CImg<int> imgTmp;
	CExternalTools::myLoadImage(strFN_Image, imgTmp);
	InitImage(imgTmp);
}

void and_or_tree::CTreeInstance::InitParsedImage(string strFN_ParsedResult)
{
	int i, j, node_type, leaf_index, tx, ty;
	double t1, t4, t5;

	char strTemp[10001];
	const CAbstractNode* pNode;
	const int* qi;

	CSimpleTypeArray<const CParsedInstance*> TempPiptrList;

	ifstream inFile(strFN_ParsedResult.c_str());

	inFile.getline(strTemp, 10000);
	InitImage(string(strTemp));
	inFile.getline(strTemp, 10000);
	inFile.getline(strTemp, 10000);
	inFile.getline(strTemp, 10000);

	ClearAllInstances();

	qi = pTree->LeafNodeIndexList.pElement;
	for ( i = 0; i < pTree->LeafNodeAmount; ++i )
	{
		leaf_index = *(qi++);
		inFile>>t1>>tx>>ty>>t4>>t5;

		this->BuildPixelInstance(ParsedInstanceList.pElement + leaf_index, true, tx + ty * W);
	}

	inFile.clear();
	inFile.close();

	for ( i = pTree->NodeAmount-1; i >= 0; --i )
	{
		pNode = pTree->GetNode(i);
		node_type = pNode->GetType();
		if (node_type == CAbstractNode::TYPE_LEAF) continue;

		if (node_type == CAbstractNode::TYPE_AND)
		{
			this->ExtractParsedInstancePtrList(TempPiptrList, i);
			t4 = t5 = 0.0;
			leaf_index = (int)TempPiptrList.Size;
			for ( j = 0; j < leaf_index; ++j )
			{
				t4 += TempPiptrList.pElement[j]->x;
				t5 += TempPiptrList.pElement[j]->y;
			}
			ParsedInstanceList.pElement[i].x = t4 / leaf_index;
			ParsedInstanceList.pElement[i].y = t5 / leaf_index;
			ParsedInstanceList.pElement[i].rotation = 0.0;
			ParsedInstanceList.pElement[i].scale = 0.0;
		}
		else
		{
			// NO USE
		}
	}
}

void and_or_tree::CTreeInstance::GenerateCandidatePixelList()
{
	int i;

	CandidatePixelList.Clear();
	for ( i = 0; i < WH; ++i )
		if (EdgeMap[i] > 0.5)
			CandidatePixelList.PushBack(i);

	CPointInRectangleRandomSampler ips;

	ips.Work(W, H, Para_GenPixelCandidate_PixMargin, Para_GenPixelCandidate_PixSampleRate, CandidatePixelList);
	CandidatePixelList = ips.SampledPixelList;
	ips.ComputeNearestSampledPointList();
	NearestCandidatePixelList = ips.NearestSampledPixelList;

	//CImg<int> imgOutput;
	//DrawCandidatePixelList(imgOutput);
	//imgOutput.display();
	//CExternalTools::mySaveImage("D:\\Users\\yuanlin\\MyData\\HiDe\\6\\ParsedImage\\leaf_candidate.jpg", imgOutput);
}

void and_or_tree::CTreeInstance::DrawCandidatePixelList(CImg<int>& imgDstRGB) const
{
	int WH3 = WH * 3;
	int i, ix, iy, jx, jy, jjx, jjy;
	int* pd;
	const int* qd;

	imgDstRGB.assign(imgSrcRGB.dimx(), imgSrcRGB.dimy(), 1, 3);
	pd = imgDstRGB.data;
	qd = imgSrcRGB.data;
	for ( i = 0; i < WH3; ++i )
		*(pd++) = 128 + *(qd++) / 2;
	qd = CandidatePixelList.pElement;
	for ( i = 0; i < (int)CandidatePixelList.Size; ++i, ++qd )
	{
		ix = *qd % W; iy = *qd / W;

		for ( jjx = 0; jjx <= 0; ++jjx ) for ( jjy = 0; jjy <= 0; ++jjy )
		//for ( jjx = 0; jjx <= +1; ++jjx ) for ( jjy = 0; jjy <= +1; ++jjy )
		//for ( jjx = -1; jjx <= +1; ++jjx ) for ( jjy = -1; jjy <= +1; ++jjy )
		{
			//if (abs(jjx)+abs(jjy) > 1) continue;

			jx = ix + jjx; jy = iy + jjy;
			if (jx<0 || jx>=W || jy<0 || jy>=H) continue;
			imgDstRGB.at(jx, jy, 0, 0) = 0;
			imgDstRGB.at(jx, jy, 0, 1) = 0;
			imgDstRGB.at(jx, jy, 0, 2) = 0;
		}
	}

	char strTemp[10001];
	sprintf_s(strTemp, "|Nodes| = %d", (int)CandidatePixelList.Size);
	CExternalTools::OutputTextToImage(imgDstRGB, strTemp, 0, 0, 255, 255, 0, 0, 0, 255);
}

void and_or_tree::CTreeInstance::BuildPixelInstance(CParsedInstance* pDstInstance, bool fShouldBeCandiate, int xy) const
{
	return BuildPixelInstance(pDstInstance, fShouldBeCandiate, xy%W+0.5, xy/W+0.5);
}

void and_or_tree::CTreeInstance::BuildPixelInstance(CParsedInstance* pDstInstance, bool fShouldBeCandiate, double x, double y) const
{
	int ix, iy;
	pDstInstance->x = x; ix = (int)(x); ix = (ix<0 ? 0 : (ix<W ? ix : W-1));
	pDstInstance->y = y; iy = (int)(y); iy = (iy<0 ? 0 : (iy<H ? iy : H-1));

	if (ix<0 || ix>=W || iy<0 || iy>=H) return; // false;

	if (fShouldBeCandiate)
	{
		int t = NearestCandidatePixelList.pElement[ix + iy * W];
		if (t != ix + iy * W)
		{
			ix = t % W; iy = t / W;
			pDstInstance->x = ix + 0.5;
			pDstInstance->y = iy + 0.5;
		}
	}

	pDstInstance->rotation = CMyMath::FormatAngle_Small(OrientationList[ix + iy * W]);
	pDstInstance->scale = 0.0;

	//return true;
}

//void and_or_tree::CTreeInstance::ExtractBasicInstancePtrList(CSimpleTypeArray<const CBasicInstance*>& DstBiptrList, int NodeIndex) const
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//
//	int i;
//	const int* qi;
//	const CAbstractNode* qNode;
//	int ChildrenAmount;
//
//	qNode = pTree->GetNode(NodeIndex);
//	ChildrenAmount = qNode->GetChildrenAmount();
//	qi = qNode->GetPtrChildrenIndex();
//	DstBiptrList.Resize(ChildrenAmount);
//	for ( i = 0; i < ChildrenAmount; ++i, ++qi )
//		DstBiptrList.pElement[i] = ParsedInstanceList.pElement + *qi;
//}
//
//void and_or_tree::CTreeInstance::ExtractBasicInstancePtrList(CSimpleTypeArray<const CBasicInstance*>& DstBiptrList, int NodeIndex, const int* pSrcChoiceIndex) const
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//
//	int i;
//	const int* qi;
//	const CAbstractNode* qNode;
//	int ChildrenAmount;
//
//	qNode = pTree->GetNode(NodeIndex);
//	ChildrenAmount = qNode->GetChildrenAmount();
//	qi = qNode->GetPtrChildrenIndex();
//	DstBiptrList.Resize(ChildrenAmount);
//	for ( i = 0; i < ChildrenAmount; ++i, ++qi, ++pSrcChoiceIndex )
//		DstBiptrList.pElement[i] = InstanceSet.pElement[*qi].pElement + *pSrcChoiceIndex;
//}

void and_or_tree::CTreeInstance::ExtractParsedInstancePtrList(CSimpleTypeArray<const CParsedInstance*>& DstPiptrList, int NodeIndex) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	int i;
	const int* qi;
	const CAbstractNode* qNode;
	int ChildrenAmount;

	qNode = pTree->GetNode(NodeIndex);
	ChildrenAmount = qNode->GetChildrenAmount();
	qi = qNode->GetPtrChildrenIndex();
	DstPiptrList.Resize(ChildrenAmount);
	for ( i = 0; i < ChildrenAmount; ++i, ++qi )
		DstPiptrList.pElement[i] = ParsedInstanceList.pElement + *qi;
}

void and_or_tree::CTreeInstance::ExtractParsedInstancePtrList(CSimpleTypeArray<const CParsedInstance*>& DstPiptrList, int NodeIndex, const int* pSrcChoiceIndex) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	int i;
	const int* qi;
	const CAbstractNode* qNode;
	int ChildrenAmount;

	qNode = pTree->GetNode(NodeIndex);
	ChildrenAmount = qNode->GetChildrenAmount();
	qi = qNode->GetPtrChildrenIndex();
	DstPiptrList.Resize(ChildrenAmount);
	for ( i = 0; i < ChildrenAmount; ++i, ++qi, ++pSrcChoiceIndex )
		DstPiptrList.pElement[i] = InstanceSet.pElement[*qi].pElement + *pSrcChoiceIndex;
}

//void and_or_tree::CTreeInstance::RefreshNodeShapeScore(double NewNodeShapeScore, int NodeIndex)
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//
//	RefreshNodeShapeScore(NewNodeShapeScore, NodeIndex, ParsedInstanceList.pElement + NodeIndex);
//}

void and_or_tree::CTreeInstance::RefreshNodeShapeScore(double NewNodeShapeScore, int NodeIndex, CParsedInstance* pDstParsedInstance) const
{
	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();
	const int* qi = qNode->GetPtrChildrenIndex();
	int i;

	pDstParsedInstance->tree_shape_score = pDstParsedInstance->node_shape_score = NewNodeShapeScore;
	for ( i = 0; i < ChildrenAmount; ++i )
	{
		const CParsedInstance& ic = this->ParsedInstanceList.pElement[qi[i]];
		pDstParsedInstance->tree_shape_score += ic.tree_shape_score;
	}
}

//void and_or_tree::CTreeInstance::RefreshNodeShapeScore(double NewNodeShapeScore, int NodeIndex, int ChoiceIndex)
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//	if (ChoiceIndex<0 || ChoiceIndex>=(int)GetInstanceList(NodeIndex).Size) return;
//
//	RefreshNodeShapeScore(NewNodeShapeScore, NodeIndex, &GetInstance(NodeIndex, ChoiceIndex));
//}

void and_or_tree::CTreeInstance::RefreshNodeShapeScore(double NewNodeShapeScore, int NodeIndex, CInstanceChoice* pDstInstanceChoice) const
{
	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();
	const int* qi = qNode->GetPtrChildrenIndex();
	const int* qci = pDstInstanceChoice->ChildrenChoiceIndexList.pElement;
	int i;

	pDstInstanceChoice->tree_shape_score = pDstInstanceChoice->node_shape_score = NewNodeShapeScore;
	for ( i = 0; i < ChildrenAmount; ++i )
	{
		const CParsedInstance& ic = this->GetInstance(qi[i], qci[i]);
		pDstInstanceChoice->tree_shape_score += ic.tree_shape_score;
	}
}

//void and_or_tree::CTreeInstance::RefreshNodeAppearanceScore(double NewNodeAppearanceScore, int NodeIndex)
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//
//	RefreshNodeAppearanceScore(NewNodeAppearanceScore, NodeIndex, ParsedInstanceList.pElement + NodeIndex);
//}

void and_or_tree::CTreeInstance::RefreshNodeAppearanceScore(double NewNodeAppearanceScore, int NodeIndex, CParsedInstance* pDstParsedInstance) const
{
	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();
	const int* qi = qNode->GetPtrChildrenIndex();
	int i;

	pDstParsedInstance->tree_appearance_score = pDstParsedInstance->node_appearance_score = NewNodeAppearanceScore;
	for ( i = 0; i < ChildrenAmount; ++i )
	{
		const CParsedInstance& ic = this->ParsedInstanceList.pElement[qi[i]];
		pDstParsedInstance->tree_appearance_score += ic.tree_appearance_score;
	}
}

//void and_or_tree::CTreeInstance::RefreshNodeAppearanceScore(double NewNodeAppearanceScore, int NodeIndex, int ChoiceIndex)
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//	if (ChoiceIndex<0 || ChoiceIndex>=(int)GetInstanceList(NodeIndex).Size) return;
//
//	RefreshNodeAppearanceScore(NewNodeAppearanceScore, NodeIndex, &GetInstance(NodeIndex, ChoiceIndex));
//}

void and_or_tree::CTreeInstance::RefreshNodeAppearanceScore(double NewNodeAppearanceScore, int NodeIndex, CInstanceChoice* pDstInstanceChoice) const
{
	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();
	const int* qi = qNode->GetPtrChildrenIndex();
	const int* qci = pDstInstanceChoice->ChildrenChoiceIndexList.pElement;
	int i;

	pDstInstanceChoice->tree_appearance_score = pDstInstanceChoice->node_appearance_score = NewNodeAppearanceScore;
	for ( i = 0; i < ChildrenAmount; ++i )
	{
		const CParsedInstance& ic = this->GetInstance(qi[i], qci[i]);
		pDstInstanceChoice->tree_appearance_score += ic.tree_appearance_score;
	}
}

//void and_or_tree::CTreeInstance::RefreshNodeTotalScore(double NewNodeShapeScore, double NewNodeAppearanceScore, int NodeIndex)
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//
//	RefreshNodeTotalScore(NewNodeShapeScore, NewNodeAppearanceScore, NodeIndex, ParsedInstanceList.pElement + NodeIndex);
//}

void and_or_tree::CTreeInstance::RefreshNodeTotalScore(double NewNodeShapeScore, double NewNodeAppearanceScore, int NodeIndex, CParsedInstance* pDstParsedInstance) const
{
	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();
	const int* qi = qNode->GetPtrChildrenIndex();
	int i;

	pDstParsedInstance->tree_shape_score = pDstParsedInstance->node_shape_score = NewNodeShapeScore;
	pDstParsedInstance->tree_appearance_score = pDstParsedInstance->node_appearance_score = NewNodeAppearanceScore;
	for ( i = 0; i < ChildrenAmount; ++i )
	{
		const CParsedInstance& ic = this->ParsedInstanceList.pElement[qi[i]];
		pDstParsedInstance->tree_shape_score += ic.tree_shape_score;
		pDstParsedInstance->tree_appearance_score += ic.tree_appearance_score;
	}
	pDstParsedInstance->RefreshTotalScore();
}

//void and_or_tree::CTreeInstance::RefreshNodeTotalScore(double NewNodeShapeScore, double NewNodeAppearanceScore, int NodeIndex, int ChoiceIndex)
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//	if (ChoiceIndex<0 || ChoiceIndex>=(int)GetInstanceList(NodeIndex).Size) return;
//
//	RefreshNodeTotalScore(NewNodeShapeScore, NewNodeAppearanceScore, NodeIndex, &GetInstance(NodeIndex, ChoiceIndex));
//}

void and_or_tree::CTreeInstance::RefreshNodeTotalScore(double NewNodeShapeScore, double NewNodeAppearanceScore, int NodeIndex, CInstanceChoice* pDstInstanceChoice) const
{
	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();
	const int* qi = qNode->GetPtrChildrenIndex();
	const int* qci = pDstInstanceChoice->ChildrenChoiceIndexList.pElement;
	int i;

	pDstInstanceChoice->tree_shape_score = pDstInstanceChoice->node_shape_score = NewNodeShapeScore;
	pDstInstanceChoice->tree_appearance_score = pDstInstanceChoice->node_appearance_score = NewNodeAppearanceScore;
	for ( i = 0; i < ChildrenAmount; ++i )
	{
		const CParsedInstance& ic = this->GetInstance(qi[i], qci[i]);
		pDstInstanceChoice->tree_shape_score += ic.tree_shape_score;
		pDstInstanceChoice->tree_appearance_score += ic.tree_appearance_score;
	}
	pDstInstanceChoice->RefreshTotalScore();
}

void and_or_tree::CTreeInstance::SetMe_AT_CAbstractTree() const
{
	CLeafNode::SetCurrentIPPFE(pIPPFE_Leaf);
}

void and_or_tree::CTreeInstance::ComputeNodeShapeFeature(
	CSimpleTypeArray<double>& DstShapeFeatureList,
	int NodeIndex, const CParsedInstance* pParsedInstance
	) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();

	CSimpleTypeArray<const CParsedInstance*> TempPiptrList;
	this->ExtractParsedInstancePtrList(TempPiptrList, NodeIndex);

	this->SetMe_AT_CAbstractTree();

	qNode->ComputeShapeFeature(DstShapeFeatureList, pParsedInstance, TempPiptrList);
}

void and_or_tree::CTreeInstance::ComputeNodeShapeFeature(
	CSimpleTypeArray<double>& DstShapeFeatureList,
	int NodeIndex, const CInstanceChoice* pInstanceChoice
	) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();

	CSimpleTypeArray<const CParsedInstance*> TempPiptrList;
	this->ExtractParsedInstancePtrList(TempPiptrList, NodeIndex, pInstanceChoice->ChildrenChoiceIndexList.pElement);

	this->SetMe_AT_CAbstractTree();

	qNode->ComputeShapeFeature(DstShapeFeatureList, pInstanceChoice, TempPiptrList);
}

void and_or_tree::CTreeInstance::ComputeTreeParsedInstanceShapeFeature(
	CSimpleTypeArray<double>& DstShapeFeatureList
	) const
{
	CSimpleTypeArray<double> tmpShapeFeatureList;

	DstShapeFeatureList.Clear();

	int i;
	for ( i = 0; i < pTree->NodeAmount; ++i )
	{
		this->ComputeNodeShapeFeature(tmpShapeFeatureList, i, ParsedInstanceList.pElement + i);
		DstShapeFeatureList.PushBack(tmpShapeFeatureList);
	}
}

void and_or_tree::CTreeInstance::ComputeNodeAppearanceFeature(
	CSimpleTypeArray<double>& DstAppearanceFeatureList,
	int NodeIndex, const CParsedInstance* pParsedInstance
	) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);

	qNode->ComputeAppearanceFeature(DstAppearanceFeatureList, pParsedInstance);
}

void and_or_tree::CTreeInstance::ComputeNodeAppearanceFeature(
	CSimpleTypeArray<double>& DstAppearanceFeatureList,
	int NodeIndex, const CInstanceChoice* pInstanceChoice
	) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);

	qNode->ComputeAppearanceFeature(DstAppearanceFeatureList, pInstanceChoice);
}

void and_or_tree::CTreeInstance::ComputeTreeParsedInstanceAppearanceFeature(
	CSimpleTypeArray<double>& DstAppearanceFeatureList
	) const
{
	CSimpleTypeArray<double> tmpAppearanceFeatureList;

	DstAppearanceFeatureList.Clear();

	int i;
	for ( i = 0; i < pTree->NodeAmount; ++i )
	{
		this->ComputeNodeAppearanceFeature(tmpAppearanceFeatureList, i, ParsedInstanceList.pElement + i);
		DstAppearanceFeatureList.PushBack(tmpAppearanceFeatureList);
	}
}

void and_or_tree::CTreeInstance::ComputeNodeFullFeature(
	CSimpleTypeArray<double>& DstShapeFeatureList,
	CSimpleTypeArray<double>& DstAppearanceFeatureList,
	int NodeIndex, const CParsedInstance* pParsedInstance
	) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();

	CSimpleTypeArray<const CParsedInstance*> TempPiptrList;
	this->ExtractParsedInstancePtrList(TempPiptrList, NodeIndex);

	this->SetMe_AT_CAbstractTree();

	qNode->ComputeShapeFeature(DstShapeFeatureList, pParsedInstance, TempPiptrList);
	qNode->ComputeAppearanceFeature(DstAppearanceFeatureList, pParsedInstance);
}

void and_or_tree::CTreeInstance::ComputeNodeFullFeature(
	CSimpleTypeArray<double>& DstShapeFeatureList,
	CSimpleTypeArray<double>& DstAppearanceFeatureList,
	int NodeIndex, const CInstanceChoice* pInstanceChoice
	) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	const CAbstractNode* qNode = pTree->GetNode(NodeIndex);
	int ChildrenAmount = qNode->GetChildrenAmount();

	CSimpleTypeArray<const CParsedInstance*> TempPiptrList;
	this->ExtractParsedInstancePtrList(TempPiptrList, NodeIndex, pInstanceChoice->ChildrenChoiceIndexList.pElement);

	this->SetMe_AT_CAbstractTree();

	qNode->ComputeShapeFeature(DstShapeFeatureList, pInstanceChoice, TempPiptrList);
	qNode->ComputeAppearanceFeature(DstAppearanceFeatureList, pInstanceChoice);
}

void and_or_tree::CTreeInstance::ComputeTreeParsedInstanceFullFeature(
	CSimpleTypeArray<double>& DstShapeFeatureList,
	CSimpleTypeArray<double>& DstAppearanceFeatureList
	) const
{
	CSimpleTypeArray<double> tmpShapeFeatureList;
	CSimpleTypeArray<double> tmpAppearanceFeatureList;

	DstShapeFeatureList.Clear();
	DstAppearanceFeatureList.Clear();

	int i;
	for ( i = 0; i < pTree->NodeAmount; ++i )
	{
		this->ComputeNodeFullFeature(tmpShapeFeatureList, tmpAppearanceFeatureList, i, ParsedInstanceList.pElement + i);
		DstShapeFeatureList.PushBack(tmpShapeFeatureList);
		DstAppearanceFeatureList.PushBack(tmpAppearanceFeatureList);
	}
}

bool and_or_tree::CTreeInstance::ParseFromTop(int RootChoiceIndex)
{
	CParsedInstance TempParsedInstance;
	TempParsedInstance.ClearAll();

	ParsedInstanceList.Fill(TempParsedInstance);

	CSimpleTypeArray<int> NodeVisitAmountList;
	NodeVisitAmountList.Resize(pTree->NodeAmount);
	NodeVisitAmountList.Fill(0);

	if (RootChoiceIndex<0 || RootChoiceIndex>=(int)InstanceSet.pElement->Size) return false;

	_ParseFromTop(0, RootChoiceIndex, NodeVisitAmountList.pElement);

	int i, t;
	CParsedInstance* ppi = ParsedInstanceList.pElement;
	for ( i = 0; i < pTree->NodeAmount; ++i, ++ppi )
	{
		t = NodeVisitAmountList.pElement[i];

		if (t < 1)
		{
			ppi->ClearAll();
			continue;
		}

		ppi->x /= t;
		ppi->y /= t;
		ppi->rotation /= t;
		ppi->scale /= t;

		ppi->node_shape_score /= t;
		ppi->node_appearance_score /= t;
		ppi->node_total_score /= t;
		ppi->tree_shape_score /= t;
		ppi->tree_appearance_score /= t;
		ppi->tree_total_score /= t;
	}

	return true;
}

void and_or_tree::CTreeInstance::_ParseFromTop(int NodeIndex, int ChoiceIndex, int* pNodeVisitAmount)
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
	const CSimpleTypeArray<CInstanceChoice>& CurrentInstanceList = GetInstanceList(NodeIndex);
	if (ChoiceIndex<0 || ChoiceIndex>=(int)CurrentInstanceList.Size) return;

	int i, ii;

	++pNodeVisitAmount[NodeIndex];

	if (pNodeVisitAmount[NodeIndex] == 1)
	{
		CInstanceChoice* qic = CurrentInstanceList.pElement;
		ii = (int)CurrentInstanceList.Size;
		for ( i = 0; i < ii; ++i, ++qic )
			qic->Tag &= ~1;
	}
	CurrentInstanceList.pElement[ChoiceIndex].Tag |= 1;

	const CInstanceChoice& src = CurrentInstanceList.pElement[ChoiceIndex];
	CParsedInstance& dst = ParsedInstanceList.pElement[NodeIndex];

	dst.x += src.x;
	dst.y += src.y;
	dst.rotation += src.rotation;
	dst.scale += src.scale;

	dst.node_shape_score += src.node_shape_score;
	dst.node_appearance_score += src.node_appearance_score;
	dst.node_total_score += src.node_total_score;
	dst.tree_shape_score += src.tree_shape_score;
	dst.tree_appearance_score += src.tree_appearance_score;
	dst.tree_total_score += src.tree_total_score;

	ii = (int)src.ChildrenChoiceIndexList.Size;
	const int* qci = pTree->GetNode(NodeIndex)->GetPtrChildrenIndex();
	const int* qcci = src.ChildrenChoiceIndexList.pElement;
	for ( i = 0; i < ii; ++i )
		_ParseFromTop(*(qci++), *(qcci++), pNodeVisitAmount);
}

void and_or_tree::CTreeInstance::DrawParsedImage(CImg<int>& imgDstRGB) const
{
	DrawParsedImage(imgDstRGB, this->GetInstance(0, 0).tree_total_score);
}

void and_or_tree::CTreeInstance::DrawPoint(CImg<int>& imgDstRGB, int x, int y, int sqr_radius, int RGB) const
{
	int W = imgDstRGB.dimx();
	int H = imgDstRGB.dimy();
	int i, j, tx, ty;
	int r = (int)(sqrt(sqr_radius * 1.0) + 0.4);
	for ( i = -r; i <= +r; ++i ) for ( j = -r; j <= +r; ++j )
	{
		if (i*i+j*j > sqr_radius) continue;
		tx = x + i; if (tx<0 || tx>=W) continue;
		ty = y + j; if (ty<0 || ty>=H) continue;
		imgDstRGB.at(tx, ty, 0, 0) = (RGB >> 16);
		imgDstRGB.at(tx, ty, 0, 1) = ((RGB >> 8) & 255);
		imgDstRGB.at(tx, ty, 0, 2) = (RGB & 255);
	}
}

void and_or_tree::CTreeInstance::DrawParsedImage(CImg<int>& imgDstRGB, double FullTreeScore) const
{
	int j, jx, jy;
	const CAbstractNode* qNode;
	const CBasicInstance* pbi;
	char strTemp[10001];

	DrawWhiteImage(imgDstRGB);

	for ( j = 0; j < pTree->NodeAmount; ++j )
	{
		qNode = pTree->GetNode(j);
		if (qNode->GetType() != CAbstractNode::TYPE_LEAF) continue;

		pbi = ParsedInstanceList.pElement + j;
		jx = (int)(pbi->x + EPS); jx = (jx<0 ? 0 : (jx<W ? jx : W-1));
		jy = (int)(pbi->y + EPS); jy = (jy<0 ? 0 : (jy<H ? jy : H-1));

		DrawPoint(imgDstRGB, jx, jy, 15, pTree->GetNodeColor(j));
	}
	sprintf_s(strTemp, "Score: %.2lf", FullTreeScore);
	CExternalTools::OutputTextToImage(imgDstRGB, strTemp, 0, 0, 255, 255, 0, 0, 0, 255);
}

void and_or_tree::CTreeInstance::DrawWhiteImage(CImg<int>& imgDstRGB) const
{
	int j;

	imgDstRGB.assign(imgSrcRGB, false);

	for ( j = 0; j < WH*3; ++j )
		imgDstRGB.data[j] = 128 + imgDstRGB.data[j] / 2;
}

void and_or_tree::CTreeInstance::DrawNodeInstanceChoiceSet(CImg<int>& imgDstRGB, int NodeIndex, bool fDrawFakeInstances) const
{
	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;

	char strTemp[100001];
	int i, t, ix, iy, ic;
	const CSimpleTypeArray<CInstanceChoice>& CurrentList = this->GetInstanceList(NodeIndex);
	const CInstanceChoice* qic;
	ic = pTree->GetNodeColor(NodeIndex);
	t = 0;
	for ( qic = CurrentList.pElement, i = 0; i < (int)CurrentList.Size; ++i, ++qic )
	{
		if (!fDrawFakeInstances && qic->fIsfake) continue;
		ix = (int)(qic->x + EPS); iy = (int)(qic->y + EPS);
		++t;
		DrawPoint(imgDstRGB, ix, iy, 4, ic);
	}
	sprintf_s(strTemp, "Amount: %d", t);
	CExternalTools::OutputTextToImage(imgDstRGB, strTemp, 0, 0, 255, 255, 0, 0, 0, 255);
}

//void and_or_tree::CTreeInstance::GetSingleTreeInstance(CSimpleTypeArray<C_old_InstanceChoice*>& DstInstancePtrList, int RootChoiceIndex) const
//{
//	DstInstancePtrList.Clear();
//	const CSimpleTypeArray<C_old_InstanceChoice>& root_list = this->Get_old_InstanceList(0);
//	if (RootChoiceIndex<0 || RootChoiceIndex>=(int)root_list.Size) return;
//
//	CSimpleTypeArray<_C_old_InstanceChoicePointer> ICP_List;
//	ICP_List.Clear();
//	_GetSingleTreeInstance(ICP_List, 0, RootChoiceIndex);
//	sort(ICP_List.Begin(), ICP_List.End());
//	int i;
//	const _C_old_InstanceChoicePointer* qd = ICP_List.pElement;
//	for ( i = 0; i < (int)ICP_List.Size; ++i, ++qd )
//		DstInstancePtrList.PushBack(this->Get_old_InstanceList(qd->node_index).pElement + qd->choice_index);
//}
//
//void and_or_tree::CTreeInstance::_GetSingleTreeInstance(CSimpleTypeArray<_C_old_InstanceChoicePointer>& Dst_ICP_List, int NodeIndex, int ChoiceIndex) const
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//	const CSimpleTypeArray<C_old_InstanceChoice>& CurrentChoiceList = this->Get_old_InstanceList(NodeIndex);
//	if (ChoiceIndex<0 || ChoiceIndex>=(int)CurrentChoiceList.Size) return;
//
//	_C_old_InstanceChoicePointer tICP;
//	tICP.index = (int)Dst_ICP_List.Size;
//	tICP.node_index = NodeIndex;
//	tICP.choice_index = ChoiceIndex;
//	Dst_ICP_List.PushBack(tICP);
//
//	int i, ii;
//	ii = (int)CurrentChoiceList.pElement[ChoiceIndex].ChildrenChoiceIndexList.Size;
//	const int* qci = pTree->GetNode(NodeIndex)->GetPtrChildrenIndex();
//	const int* qcci = CurrentChoiceList.pElement[ChoiceIndex].ChildrenChoiceIndexList.pElement;
//	for ( i = 0; i < ii; ++i )
//		_GetSingleTreeInstance(Dst_ICP_List, *(qci++), *(qcci++));
//}

void and_or_tree::CTreeInstance::OutputSizeInformation(ostream& outStream) const
{
	int i;
	for ( i = 0; i < (int)InstanceSet.Size; ++i )
		outStream<<" "<<InstanceSet.pElement[i].GetRealSize();
	outStream<<endl;
}

//void and_or_tree::CTreeInstance::TagUsefulInstanceChoicesFromTop(int NodeIndex, int ChoiceIndex)
//{
//	int i, j;
//	for ( i = 0; i < pTree->NodeAmount; ++i )
//	{
//		CSimpleTypeArray<C_old_InstanceChoice>& cur_ic_list = this->Get_old_InstanceList(i);
//		C_old_InstanceChoice* pic = cur_ic_list.pElement;
//		for ( j = 0; j < (int)cur_ic_list.Size; ++j, ++pic )
//			pic->tag &= (~4);
//	}
//	__TagUsefulInstanceChoicesFromTop(NodeIndex, ChoiceIndex);
//}
//
//void and_or_tree::CTreeInstance::__TagUsefulInstanceChoicesFromTop(int NodeIndex, int ChoiceIndex)
//{
//	if (NodeIndex<0 || NodeIndex>=pTree->NodeAmount) return;
//	const CSimpleTypeArray<C_old_InstanceChoice>& CurrentInstanceList = Get_old_InstanceList(NodeIndex);
//	if (ChoiceIndex<0 || ChoiceIndex>=(int)CurrentInstanceList.Size) return;
//
//	C_old_InstanceChoice& CurrentInstance = Get_old_Instance(NodeIndex, ChoiceIndex);
//	CurrentInstance.tag |= 4;
//
//	C_old_NodeInstance new_Instance = *((const C_old_NodeInstance *)(&CurrentInstance));
//	int i, ii;
//	ii = (int)CurrentInstance.ChildrenChoiceIndexList.Size;
//	const int* qci = pTree->GetNode(NodeIndex)->GetPtrChildrenIndex();
//	const int* qcci = CurrentInstance.ChildrenChoiceIndexList.pElement;
//	for ( i = 0; i < ii; ++i )
//		__TagUsefulInstanceChoicesFromTop(*(qci++), *(qcci++));
//}

